﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using FCS.GlobalComponents;
using Microsoft.Win32;
using System.IO;
using FCS.Pattern;
using System.Threading;
using System.Windows.Threading;

namespace BollardMusic
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        // This collection is associated with the UI. Any changes to this will be immediately reflected by the UI
        ObservableCollection<ViewData> _bollardDataCollection = new ObservableCollection<ViewData>();
        BollardController _controller = new BollardController(false);
        CommandPriority _cp = CommandPriority.music;
        bool _isPlayingMusic = false;

        int _randomPlayDelay = 2;
        System.Timers.Timer _randomPlayTimer = new System.Timers.Timer();

        object _monitor = new object();
        bool _isListeningForBollards = true;

        public MainWindow()
        {
            InitializeComponent();

            // initialize the lists
            for (int i = 0; i < FountainConstants.BollardCount; i++)
                _bollardDataCollection.Add(new ViewData { BollardNumber = (i + 1), SequenceFile = "No Sequence", MusicFile = "No Music" });

            // start listening for bollard input
            new Thread(() => { ProcessBollardInput(); }).Start();

            // disable the timer slider until it is ready to be used
            timerSlider.IsEnabled = false;

            _randomPlayTimer.Elapsed += new System.Timers.ElapsedEventHandler(_randomPlayTimer_Elapsed);
        }

        /// <summary>
        /// Once the timer has elapsed, play one of the random bollards
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void _randomPlayTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            // check to see which bollards are filled in
            bool[] filled = new bool[_bollardDataCollection.Count];
            bool isAtLeastOneActive = false;

            for (int i = 0; i < _bollardDataCollection.Count; i++)
            {
                if (_bollardDataCollection.ElementAt(i).SequenceFile != "No Sequence")
                {
                    filled[i] = true;
                    isAtLeastOneActive = true;
                }
                else
                    filled[i] = false;
            }

            if (isAtLeastOneActive)
            {
                Random r = new Random();
                int i = r.Next(0, _bollardDataCollection.Count); // chose a random bollard

                // choose one that is filled only
                while (!filled[i])
                    i = r.Next(0, 4);

                // play the pattern
                PlayPattern(i);
            }

        }

        public ObservableCollection<ViewData> BollardDataCollection
        { get { return _bollardDataCollection; } }


        /// <summary>
        /// This will read in a configuration file that has the location of the *.ptrn and *.mp3 files
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void assignBollards(object sender, RoutedEventArgs e)
        {
            string strFileName;
            int selectedBollard = bollardListView.SelectedIndex;

            // no bollards are selected
            if (selectedBollard == -1)
            {
                MessageBox.Show("Error: No bollards yet selected. You must first select a bollard before it can be assigned.", "Bollard Music Controller");
            }

            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Filter = "bollard config file (*.mbsf)|*.mbsf|All files (*.*)|*.*";
            dialog.Title = "Select a musical bollard pattern file";

            dialog.ShowDialog();

            strFileName = dialog.FileName;

            // return if the filename is empty (user didn't choose anything)
            if (strFileName == String.Empty)
                return;

            StreamReader sr = new StreamReader(strFileName);
            string sequence = sr.ReadLine();
            string musicFile = sr.ReadLine();


            // load patterns
            Pattern p = _controller.ReadPattern(sequence);
            _controller.LoadPatternAtIndex(p, selectedBollard);

            // update UI
            _bollardDataCollection.RemoveAt(selectedBollard);
            _bollardDataCollection.Insert(selectedBollard, new ViewData { BollardNumber = selectedBollard + 1, SequenceFile = sequence, MusicFile = musicFile });
        }

        /// <summary>
        /// Pulls input from cRIO and decides if bollards should play
        /// </summary>
        private void ProcessBollardInput()
        {
            cRIOState state;

            while (true)
            {
                state = _controller.GetState();
                bool[] bollardStates = state.BollardStates;
                bool isListening;

                lock (_monitor)
                    isListening = _isListeningForBollards;

                for (int i = 0; i < FountainConstants.BollardCount; i++)
                {
                    if (bollardStates[i] && isListening)
                        _controller.PlayPattern(i, CommandPriority.music);
                }
            }
        }

        /// <summary>
        /// Plays the selected bollard's sequence and music when the play button is clicked
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void playBollardButton_Click(object sender, RoutedEventArgs e)
        {
            int selectedBollard = bollardListView.SelectedIndex;
            if (selectedBollard == -1)
                return;

            PlayPattern(selectedBollard);
        }

        /// <summary>
        /// Plays a selected pattern and it's assoc music
        /// </summary>
        /// <param name="selectedBollard"></param>
        private void PlayPattern(int selectedBollard)
        {
            this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => { 
                timerSlider.IsEnabled = false;
                playSongRandCheckBox.IsEnabled = false;
            }));

            if (!_isPlayingMusic)
            {
                _isPlayingMusic = true;
                _controller.SendStopPattern();

                MediaPlayer player = new MediaPlayer();
                string musicSource = _bollardDataCollection.ElementAt(selectedBollard).MusicFile;
                player.Open(new Uri(musicSource, UriKind.Relative));




                player.Play(); // controls the music player
                _controller.PlayPattern(selectedBollard, CommandPriority.music);// start the pattern
                this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() =>
                {
                    if((bool)playSongRandCheckBox.IsChecked)
                        timerSlider.IsEnabled = true;
                    playSongRandCheckBox.IsEnabled = true;
                }));
                player.Stop();

                _controller.SendStopPattern();
                _controller.ResetThreshold(_cp);
                _isPlayingMusic = false;
            }
        }

        /// <summary>
        /// Toggles when the program should ignore the bollard input
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ignoreBollardCheckBox_Checked(object sender, RoutedEventArgs e)
        {
                _isListeningForBollards = !_isListeningForBollards;
        }

        /// <summary>
        /// Updates the delay when the timer slider is changed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timerSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (minutesLabel == null)
                return;

            SetTimer();
            
        }

        /// <summary>
        /// Sets up when the random play timer will trigger a random play
        /// </summary>
        private void SetTimer()
        {
            if (!_isPlayingMusic)
            {
                minutesLabel.Content = ((int)timerSlider.Value) + " minutes";
                //_randomPlayDelay = ((int)timerSlider.Value) * 1000 * 60; // convert from ms to seconds to minutes
                _randomPlayDelay = ((int)timerSlider.Value) * 1000; // convert from ms to seconds

                _randomPlayTimer.Interval = _randomPlayDelay;
                _randomPlayTimer.Enabled = true;
            }
        }

        /// <summary>
        /// Enables the timer when the check box is checked
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void playSongRandCheckBox_Click(object sender, RoutedEventArgs e)
        {
            CheckBox cb = (CheckBox)sender;
            bool? isChecked = cb.IsChecked;
            if (isChecked == true)
            {
                playBollardButton.IsEnabled = false;
                timerSlider.IsEnabled = true;
            }
            else
            {
                playBollardButton.IsEnabled = true;
                timerSlider.IsEnabled = false;
            }

                SetTimer();
        }
    }

    public class ViewData
    {
        public int BollardNumber { get; set; }
        public string SequenceFile { get; set; }
        public string MusicFile { get; set; }
    }
}
